package structs

import (
	"encoding/binary"
	"golang.org/x/text/encoding/simplifiedchinese"
	"strings"
	"time"
)

// PacketBody 表示包体结构体
type PacketBody struct {
	reserved1      [136]uint8        // 预留字段
	alarmType      uint32            // 报警触发类型
	liveCapTime    *dateTime         // 实时数据抓拍时间
	serialNum      uint32            // 车辆流水号
	reserved2      [75]uint8         // 预留字段
	falsePlate     uint32            // 是否虚假车牌
	reserved3      [28]uint8         // 预留字段
	offlineCapTime *dateTime         // 离线数据抓拍时间
	reserved4      [12]uint8         // 预留字段
	direction      uint32            // 车辆方向
	speed          uint32            // 车辆速度
	vehicleColor   [32]uint8         // 车辆颜色
	plateColor     [32]uint8         // 车牌颜色
	havePlate      uint32            // 是否存在车牌
	plateInfo      *licensePlateInfo // 车牌信息
	picWidth       uint16            // 图片宽度
	picHeight      uint16            // 图片高度
	picDataLen     uint32            // 图片数据长度
	pictureData    []byte            // 图片数据
	dataType       uint16            // 数据类型
	dataLength     uint16            // 数据长度
	data           []byte            // 通用数据
}

func ParseBody(data []byte) (*PacketBody, error) {
	//var dataTypeCursor = 536 + getPicDataLen(data[532:536])
	//var dataLengthCursor = dataTypeCursor + 2
	//var dataCursor = dataLengthCursor + 2
	body := &PacketBody{
		reserved1:      [136]uint8{},                                 // 初始化预留字段 136字节
		alarmType:      binary.LittleEndian.Uint32(data[136:140]),    // 报警触发类型 4字节
		liveCapTime:    parseDateTime(data[140:156]),                 // 实时数据抓拍时间 16字节
		serialNum:      binary.LittleEndian.Uint32(data[156:160]),    // 车辆流水号 4字节
		reserved2:      [75]uint8{},                                  // 初始化预留字段 75字节
		falsePlate:     uint32(data[235]),                            // 是否虚假车牌 1字节
		reserved3:      [28]uint8{},                                  // 初始化预留字段 28字节
		offlineCapTime: parseDateTime(data[264:280]),                 // 离线数据抓拍时间 16字节
		reserved4:      [12]uint8{},                                  // 初始化预留字段 12字节
		direction:      binary.LittleEndian.Uint32(data[292:296]),    // 车辆方向 4字节
		speed:          binary.LittleEndian.Uint32(data[296:300]),    // 车辆速度 4字节
		vehicleColor:   [32]uint8{},                                  // 车辆颜色 32字节
		plateColor:     [32]uint8{},                                  // 车牌颜色 32字节
		havePlate:      binary.LittleEndian.Uint32(data[364:368]),    // 是否存在车牌 4字节
		plateInfo:      parsePlateInfo(data[368:528]),                // 车牌信息 160字节
		picWidth:       binary.LittleEndian.Uint16(data[528:530]),    // 图片宽度 2字节
		picHeight:      binary.LittleEndian.Uint16(data[530:532]),    // 图片高度 2字节
		picDataLen:     binary.LittleEndian.Uint32(data[532:536]),    // 图片数据长度N 4字节
		pictureData:    data[536 : 536+getPicDataLen(data[532:536])], // 图片数据 N字节
		//dataType:       binary.LittleEndian.Uint16(data[dataTypeCursor : dataTypeCursor+2]),     // 数据类型 2字节
		//dataLength:     binary.LittleEndian.Uint16(data[dataLengthCursor : dataLengthCursor+2]), // 数据长度M 2字节
		//data:           data[dataCursor:],                                                       // 数据 M字节
		// ...
	}
	return body, nil
}
func getPicDataLen(data []byte) int {
	return int(binary.LittleEndian.Uint32(data[:4]))
}

// ----------------------------------------------------------------------
// dateTime 表示时间结构体，私有化
type dateTime struct {
	year, month, weekday, day, hour, minute, second, milliseconds uint16
}

func parseDateTime(data []byte) *dateTime {
	lcp := &dateTime{
		year:         binary.LittleEndian.Uint16(data[0:2]),
		month:        binary.LittleEndian.Uint16(data[2:4]),
		weekday:      binary.LittleEndian.Uint16(data[4:6]),
		day:          binary.LittleEndian.Uint16(data[6:8]),
		hour:         binary.LittleEndian.Uint16(data[8:10]),
		minute:       binary.LittleEndian.Uint16(data[10:12]),
		second:       binary.LittleEndian.Uint16(data[12:14]),
		milliseconds: binary.LittleEndian.Uint16(data[14:16]),
	}
	return lcp
}

// DateTimeToStamp 将 dateTime 结构体转换为 Unix 时间戳
func DateTimeToStamp(lcp *dateTime) int {
	// 创建 time.Time 对象
	loc, _ := time.LoadLocation("Asia/Shanghai")
	t := time.Date(
		int(lcp.year),
		time.Month(int(lcp.month)),
		int(lcp.day),
		int(lcp.hour),
		int(lcp.minute),
		int(lcp.second),
		int(lcp.milliseconds)*1e6, // 将毫秒转换为纳秒
		loc,
	)
	return int(t.Unix())
}

// ----------------------------------------------------------------------
// licensePlateInfo 表示车牌信息结构体，私有化
type licensePlateInfo struct {
	licensePlate string // 车牌号
	confidence   int    // 车牌置信度
	plateColor   uint32 // 车牌颜色
	plateType    uint32 // 车牌类型
	bodyColor    uint32 // 车身颜色
}

func parsePlateInfo(data []byte) *licensePlateInfo {
	lpi := &licensePlateInfo{
		licensePlate: encodingLicensePlate(data[:16]),                // 车牌号
		confidence:   int(binary.LittleEndian.Uint32(data[108:112])), // 车牌置信度
		plateColor:   binary.LittleEndian.Uint32(data[112:116]),      // 车牌颜色
		plateType:    binary.LittleEndian.Uint32(data[116:120]),      // 车牌类型
		bodyColor:    binary.LittleEndian.Uint32(data[120:124]),      // 车身颜色

	}
	return lpi
}
func encodingLicensePlate(data []byte) string {
	gbkDecoder := simplifiedchinese.GBK.NewDecoder()
	r, err := gbkDecoder.String(string(data[:16]))

	if err != nil {
		return "车牌解析错误"
	}
	// 去除非打印字符（例如 \x00）
	cleanedData := strings.TrimFunc(r, func(r rune) bool {
		return r == '\x00' // 去除 \x00 字符
	})

	return cleanedData
}

func getDataLen(data []byte) int {
	return int(binary.LittleEndian.Uint32(data[:2]))
}
func (p *PacketBody) GetReserved1() [136]uint8 {
	return p.reserved1
}
func (p *PacketBody) SetReserved1(reserved1 [136]uint8) {
	p.reserved1 = reserved1
}
func (p *PacketBody) GetAlarmType() uint32 {
	return p.alarmType
}
func (p *PacketBody) SetAlarmType(alarmType uint32) {
	p.alarmType = alarmType
}
func (p *PacketBody) GetLiveCapTime() *dateTime {
	return p.liveCapTime
}
func (p *PacketBody) SetLiveCapTime(liveCapTime *dateTime) {
	p.liveCapTime = liveCapTime
}
func (p *PacketBody) GetSerialNum() uint32 {
	return p.serialNum
}
func (p *PacketBody) SetSerialNum(serialNum uint32) {
	p.serialNum = serialNum
}
func (p *PacketBody) GetReserved2() [75]uint8 {
	return p.reserved2
}
func (p *PacketBody) SetReserved2(reserved2 [75]uint8) {
	p.reserved2 = reserved2
}
func (p *PacketBody) GetFalsePlate() uint32 {
	return p.falsePlate
}
func (p *PacketBody) SetFalsePlate(falsePlate uint32) {
	p.falsePlate = falsePlate
}
func (p *PacketBody) GetReserved3() [28]uint8 {
	return p.reserved3
}
func (p *PacketBody) SetReserved3(reserved3 [28]uint8) {
	p.reserved3 = reserved3
}
func (p *PacketBody) GetOfflineCapTime() *dateTime {
	return p.offlineCapTime
}
func (p *PacketBody) SetOfflineCapTime(offlineCapTime *dateTime) {
	p.offlineCapTime = offlineCapTime
}
func (p *PacketBody) GetReserved4() [12]uint8 {
	return p.reserved4
}
func (p *PacketBody) SetReserved4(reserved4 [12]uint8) {
	p.reserved4 = reserved4
}
func (p *PacketBody) GetDirection() uint32 {
	return p.direction
}
func (p *PacketBody) SetDirection(direction uint32) {
	p.direction = direction
}
func (p *PacketBody) GetSpeed() uint32 {
	return p.speed
}
func (p *PacketBody) SetSpeed(speed uint32) {
	p.speed = speed
}
func (p *PacketBody) GetVehicleColor() [32]uint8 {
	return p.vehicleColor
}
func (p *PacketBody) SetVehicleColor(vehicleColor [32]uint8) {
	p.vehicleColor = vehicleColor
}
func (p *PacketBody) GetPlateColor() [32]uint8 {
	return p.plateColor
}
func (p *PacketBody) SetPlateColor(plateColor [32]uint8) {
	p.plateColor = plateColor
}
func (p *PacketBody) GetHavePlate() uint32 {
	return p.havePlate
}
func (p *PacketBody) SetHavePlate(havePlate uint32) {
	p.havePlate = havePlate
}
func (p *PacketBody) GetPlateInfo() *licensePlateInfo {
	return p.plateInfo
}
func (p *PacketBody) SetPlateInfo(plateInfo *licensePlateInfo) {
	p.plateInfo = plateInfo
}
func (p *PacketBody) GetPicWidth() uint16 {
	return p.picWidth
}
func (p *PacketBody) SetPicWidth(picWidth uint16) {
	p.picWidth = picWidth
}
func (p *PacketBody) GetPicHeight() uint16 {
	return p.picHeight
}
func (p *PacketBody) SetPicHeight(picHeight uint16) {
	p.picHeight = picHeight
}
func (p *PacketBody) GetPicDataLen() uint32 {
	return p.picDataLen
}
func (p *PacketBody) SetPicDataLen(picDataLen uint32) {
	p.picDataLen = picDataLen
}
func (p *PacketBody) GetPictureData() []byte {
	return p.pictureData
}

// 注意：通常不提供setter方法，因为复制整个字节数组可能会导致性能问题
// 如果确实需要更新图片数据，可以考虑传递一个新的切片，并在这里复制数据
func (p *PacketBody) GetDataType() uint16 {
	return p.dataType
}
func (p *PacketBody) SetDataType(dataType uint16) {
	p.dataType = dataType
}

func (p *PacketBody) GetDataLength() uint16 {
	return p.dataLength
}

func (p *PacketBody) SetDataLength(dataLength uint16) {
	p.dataLength = dataLength
}

func (p *PacketBody) GetData() []byte {
	return p.data
}

// 由于切片可能会非常大，所以不提供setter方法，而是提供一个更新数据的函数
func (p *PacketBody) UpdateData(newData []byte) {
	p.data = make([]byte, len(newData))
	copy(p.data, newData)
}
func (l *licensePlateInfo) SetLicensePlate(licensePlate string) {
	l.licensePlate = licensePlate
}

func (l *licensePlateInfo) GetLicensePlate() string {
	return l.licensePlate
}

func (l *licensePlateInfo) SetConfidence(confidence int) {
	l.confidence = confidence
}

func (l *licensePlateInfo) GetConfidence() int {
	return l.confidence
}

func (l *licensePlateInfo) SetPlateColor(plateColor uint32) {
	l.plateColor = plateColor
}

func (l *licensePlateInfo) GetPlateColor() uint32 {
	return l.plateColor
}

func (l *licensePlateInfo) SetPlateType(plateType uint32) {
	l.plateType = plateType
}

func (l *licensePlateInfo) GetPlateType() uint32 {
	return l.plateType
}

func (l *licensePlateInfo) SetBodyColor(bodyColor uint32) {
	l.bodyColor = bodyColor
}

func (l *licensePlateInfo) GetBodyColor() uint32 {
	return l.bodyColor
}
